home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
334_01
/
graphics.c
< prev
next >
Wrap
Text File
|
1991-02-04
|
37KB
|
1,309 lines
/* GNUPLOT - graphics.c */
/*
* Copyright (C) 1986, 1987, 1990 Thomas Williams, Colin Kelley
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the modified code. Modifications are to be distributed
* as patches to released version.
*
* This software is provided "as is" without express or implied warranty.
*
*
* AUTHORS
*
* Original Software:
* Thomas Williams, Colin Kelley.
*
* Gnuplot 2.0 additions:
* Russell Lang, Dave Kotz, John Campbell.
*
* send your comments or suggestions to (pixar!info-gnuplot@sun.com).
*
*/
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include "plot.h"
#include "setshow.h"
extern char *strcpy(),*strncpy(),*strcat();
void plot_impulses();
void plot_lines();
void plot_points();
void plot_dots();
void edge_intersect();
BOOLEAN two_edge_intersect();
#ifndef max /* Lattice C has max() in math.h, but shouldn't! */
#define max(a,b) ((a > b) ? a : b)
#endif
#ifndef min
#define min(a,b) ((a < b) ? a : b)
#endif
#define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
/* Define the boundary of the plot
* These are computed at each call to do_plot, and are constant over
* the period of one do_plot. They actually only change when the term
* type changes and when the 'set size' factors change.
*/
static int xleft, xright, ybot, ytop;
/* Boundary and scale factors, in user coordinates */
/* x_min, x_max, y_min, y_max are local to this file and
* are not the same as variables of the same names in other files
*/
static double x_min, x_max, y_min, y_max;
static double xscale, yscale;
/* And the functions to map from user to terminal coordinates */
#define map_x(x) (int)(xleft+(x-x_min)*xscale+0.5) /* maps floating point x to screen */
#define map_y(y) (int)(ybot+(y-y_min)*yscale+0.5) /* same for y */
/* (DFK) Watch for cancellation error near zero on axes labels */
#define SIGNIF (0.01) /* less than one hundredth of a tic mark */
#define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
#define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
/* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog
* macro, so I write it as a function on that machine.
*/
#ifndef sun386
/* (DFK) Use 10^x if logscale is in effect, else x */
#define CheckLog(log, x) ((log) ? pow(10., (x)) : (x))
#else
static double
CheckLog(log, x)
BOOLEAN log;
double x;
{
if (log)
return(pow(10., x));
else
return(x);
}
#endif /* sun386 */
double
LogScale(coord, islog, what, axis)
double coord; /* the value */
BOOLEAN islog; /* is this axis in logscale? */
char *what; /* what is the coord for? */
char *axis; /* which axis is this for ("x" or "y")? */
{
if (islog) {
if (coord <= 0.0) {
char errbuf[100]; /* place to write error message */
(void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
what, axis, coord);
(*term_tbl[term].text)();
(void) fflush(outfile);
int_error(errbuf, NO_CARET);
} else
return(log10(coord));
}
return(coord);
}
/* borders of plotting area */
/* computed once on every call to do_plot */
boundary(scaling)
BOOLEAN scaling; /* TRUE if terminal is doing the scaling */
{
register struct termentry *t = &term_tbl[term];
xleft = (t->h_char)*12;
xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
ybot = (t->v_char)*5/2 + 1;
ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*3/2 - 1;
}
double dbl_raise(x,y)
double x;
int y;
{
register int i;
double val;
val = 1.0;
for (i=0; i < abs(y); i++)
val *= x;
if (y < 0 ) return (1.0/val);
return(val);
}
double make_tics(tmin,tmax,logscale)
double tmin,tmax;
BOOLEAN logscale;
{
register double xr,xnorm,tics,tic,l10;
xr = fabs(tmin-tmax);
l10 = log10(xr);
if (logscale) {
tic = dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
if (tic < 1.0)
tic = 1.0;
} else {
xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
if (xnorm <= 2)
tics = 0.2;
else if (xnorm <= 5)
tics = 0.5;
else tics = 1.0;
tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
}
return(tic);
}
do_plot(plots, pcount, min_x, max_x, min_y, max_y)
struct curve_points *plots;
int pcount; /* count of plots in linked list */
double min_x, max_x;
double min_y, max_y;
{
register struct termentry *t = &term_tbl[term];
register int curve, xaxis_y, yaxis_x;
register struct curve_points *this_plot;
register double ytic, xtic;
register int xl, yl;
/* only a Pyramid would have this many registers! */
double xtemp, ytemp;
struct text_label *this_label;
struct arrow_def *this_arrow;
BOOLEAN scaling;
/* store these in variables global to this file */
/* otherwise, we have to pass them around a lot */
x_min = min_x;
x_max = max_x;
y_min = min_y;
y_max = max_y;
if (polar) {
/* will possibly change x_min, x_max, y_min, y_max */
polar_xform(plots,pcount);
}
if (y_min == VERYLARGE || y_max == -VERYLARGE)
int_error("all points undefined!", NO_CARET);
if (x_min == VERYLARGE || x_max == -VERYLARGE)
int_error("all points undefined!", NO_CARET);
/* Apply the desired viewport offsets. */
if (y_min < y_max) {
y_min -= boff;
y_max += toff;
} else {
y_max -= boff;
y_min += toff;
}
if (x_min < x_max) {
x_min -= loff;
x_max += roff;
} else {
x_max -= loff;
x_min += roff;
}
/* SETUP RANGES, SCALES AND TIC PLACES */
if (ytics && yticdef.type == TIC_COMPUTED) {
ytic = make_tics(y_min,y_max,log_y);
if (autoscale_ly) {
if (y_min < y_max) {
y_min = ytic * floor(y_min/ytic);
y_max = ytic * ceil(y_max/ytic);
}
else { /* reverse axis */
y_min = ytic * ceil(y_min/ytic);
y_max = ytic * floor(y_max/ytic);
}
}
}
if (xtics && xticdef.type == TIC_COMPUTED) {
xtic = make_tics(x_min,x_max,log_x);
if (autoscale_lx) {
if (x_min < x_max) {
x_min = xtic * floor(x_min/xtic);
x_max = xtic * ceil(x_max/xtic);
} else {
x_min = xtic * ceil(x_min/xtic);
x_max = xtic * floor(x_max/xtic);
}
}
}
/* This used be x_max == x_min, but that caused an infinite loop once. */
if (fabs(x_max - x_min) < zero)
int_error("x_min should not equal x_max!",NO_CARET);
if (fabs(y_max - y_min) < zero)
int_error("y_min should not equal y_max!",NO_CARET);
/* INITIALIZE TERMINAL */
if (!term_init) {
(*t->init)();
term_init = TRUE;
}
screen_ok = FALSE;
scaling = (*t->scale)(xsize, ysize);
(*t->graphics)();
/* now compute boundary for plot (xleft, xright, ytop, ybot) */
boundary(scaling);
/* SCALE FACTORS */
yscale = (ytop - ybot)/(y_max - y_min);
xscale = (xright - xleft)/(x_max - x_min);
/* DRAW AXES */
(*t->linetype)(-1); /* axis line type */
xaxis_y = map_y(0.0);
yaxis_x = map_x(0.0);
if (xaxis_y < ybot)
xaxis_y = ybot; /* save for impulse plotting */
else if (xaxis_y >= ytop)
xaxis_y = ytop ;
else if (xzeroaxis && !log_y) {
(*t->move)(xleft,xaxis_y);
(*t->vector)(xright,xaxis_y);
}
if (yzeroaxis && !log_x && yaxis_x >= xleft && yaxis_x < xright ) {
(*t->move)(yaxis_x,ybot);
(*t->vector)(yaxis_x,ytop);
}
/* DRAW TICS */
(*t->linetype)(-2); /* border linetype */
/* label y axis tics */
if (ytics) {
switch (yticdef.type) {
case TIC_COMPUTED: {
if (y_min < y_max)
draw_ytics(ytic * floor(